﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Transactions;
using System.Data.SqlClient;

using Global.Class.Library;
using DataTransferObject;
using DataTransferObject.MetaDataList;
using DataAccessLayer;
using DataAccessLayer.MetaDataList;
using DataAccessLayer.MetaDataList.ListStaffNameDTSTableAdapters;

namespace BusinessLogicLayer.MetaDataList
{
    public class ListStaffNameBLL : NotifyPropertyChangeObject
    {
        public GlobalEnum.TaskID TaskID { get { return GlobalEnum.TaskID.ListStaffName; } }

        private UserInformation userOrganization;

        private ListStaffNameMaster listStaffNameMaster;

        private BindingList<ListStaffNameDetail> listStaffNameDetailList;



        public ListStaffNameBLL()
        {
            try
            {
                if (GlobalVariables.shouldRestoreProcedure) RestoreProcedure();


                userOrganization = new UserInformation();

                listStaffNameMaster = new ListStaffNameMaster();

                this.listStaffNameDetailList = new BindingList<ListStaffNameDetail>();

                GlobalDefaultValue.Apply(this);


                this.ListStaffNameMaster.PropertyChanged += new PropertyChangedEventHandler(ListStaffNameMaster_PropertyChanged);

                this.ListStaffNameDetailList.ListChanged += new ListChangedEventHandler(ListStaffNameDetailList_ListChanged);

            }
            catch (Exception exception)
            {
                throw exception;
            }
        }

        private void ListStaffNameMaster_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.SetDirty();
        }

        private void ListStaffNameDetailList_ListChanged(object sender, ListChangedEventArgs e)
        {
            this.SetDirty();
        }




        #region <Adapter>

        private ListStaffNameListingTableAdapter listingTableAdapter;
        protected ListStaffNameListingTableAdapter ListingTableAdapter
        {
            get
            {
                if (listingTableAdapter == null) listingTableAdapter = new ListStaffNameListingTableAdapter();
                return listingTableAdapter;
            }
        }

        private ListStaffNameTableAdapter masterTableAdapter;
        protected ListStaffNameTableAdapter MasterTableAdapter
        {
            get
            {
                if (masterTableAdapter == null) masterTableAdapter = new ListStaffNameTableAdapter();
                return masterTableAdapter;
            }
        }

        private ListStaffNameDetailTableAdapter detailTableAdapter;
        protected ListStaffNameDetailTableAdapter DetailTableAdapter
        {
            get
            {
                if (detailTableAdapter == null) detailTableAdapter = new ListStaffNameDetailTableAdapter();
                return detailTableAdapter;
            }
        }


        #endregion <Adapter>

        #region <Storage>

        public UserInformation UserOrganization
        {
            get { return this.userOrganization; }
            set { this.userOrganization = value; }
        }

        public ListStaffNameDTS.ListStaffNameListingDataTable ListStaffNameListing()
        {
            return this.ListingTableAdapter.GetData();
        }

        public ListStaffNameMaster ListStaffNameMaster
        {
            get { return this.listStaffNameMaster; }
        }

        public BindingList<ListStaffNameDetail> ListStaffNameDetailList
        {
            get { return this.listStaffNameDetailList; }
        }


        #endregion <Storage>

        #region Properties

        #region <Primary Key>

        public int StaffID   //Primary Key
        {
            get { return this.ListStaffNameMaster.StaffID; }
            private set
            {
                if (this.ListStaffNameMaster.StaffID != value)
                {
                    this.StopTracking();

                    this.ListStaffNameMaster.StaffID = value;

                    this.ListStaffNameGetMaster();
                    this.ListStaffNameGetDetail();

                    this.StartTracking();
                    this.Reset();
                }

            }
        }

        #endregion <Primary Key>

        private void ListStaffNameGetMaster()
        {
            if (this.StaffID > 0)
            {
                ListStaffNameDTS.ListStaffNameDataTable masterDataTable = this.MasterTableAdapter.GetData(this.StaffID);

                if (masterDataTable.Count > 0)
                {
                    this.ListStaffNameMaster.StopTracking();

                    this.ListStaffNameMaster.EntryDate = masterDataTable[0].EntryDate;

                    this.ListStaffNameMaster.StaffCategoryID = masterDataTable[0].StaffCategoryID;
 
                    this.ListStaffNameMaster.Description = masterDataTable[0].Description;
                    this.ListStaffNameMaster.DescriptionOfficial = masterDataTable[0].DescriptionOfficial;
                    this.ListStaffNameMaster.DescriptionOriginal = masterDataTable[0].DescriptionOriginal;

                    this.ListStaffNameMaster.InActive = masterDataTable[0].InActive;

                    this.ListStaffNameMaster.StartTracking();

                    this.ListStaffNameMaster.Reset();

                    this.UserOrganization.UserID = masterDataTable[0].UserID;
                    this.UserOrganization.UserOrganizationID = masterDataTable[0].UserOrganizationID;
                }
                else throw new System.ArgumentException("Insufficient get data");
            }
            else
            {
                GlobalDefaultValue.Apply(this.ListStaffNameMaster);
                this.ListStaffNameMaster.EntryDate = DateTime.Today;
                this.ListStaffNameMaster.Reset();
            }
        }


        private void ListStaffNameGetDetail()
        {
            this.listStaffNameDetailList.RaiseListChangedEvents = false;
            this.listStaffNameDetailList.Clear();
            if (this.StaffID >= 0)
            {

                ListStaffNameDTS.ListStaffNameDetailDataTable detailDataTable = this.DetailTableAdapter.GetData(this.StaffID);

                if (detailDataTable.Count > 0)
                {
                    foreach (ListStaffNameDTS.ListStaffNameDetailRow detailRow in detailDataTable.Rows)
                    {
                        this.listStaffNameDetailList.Add(new ListStaffNameDetail(detailRow.CommonID, detailRow.CommonValue, detailRow.Remarks));
                    }
                }
            }
            this.listStaffNameDetailList.RaiseListChangedEvents = true;
            this.listStaffNameDetailList.ResetBindings();
        }

        #endregion Properties





        #region Object Permission

        public override bool IsValid
        {
            get
            {
                List<ListStaffNameDetail> inValidListStaffNameDetail = this.ListStaffNameDetailList.Where(listStaffNameDetail => !listStaffNameDetail.IsValid).ToList();
                return this.ListStaffNameMaster.IsValid && inValidListStaffNameDetail.Count == 0;
            }
        }

        public bool ReadOnly
        {
            get
            {
                try
                {
                    return GlobalUserPermission.GetUserReadOnly(GlobalVariables.GlobalUserInformation.UserID, this.TaskID);
                }
                catch
                {
                    return true;
                }
            }
        }

        public bool Editable
        {
            get
            {
                try
                {
                    if (!GlobalUserPermission.GetUserEditable(GlobalVariables.GlobalUserInformation.UserID, this.TaskID, this.UserOrganization.UserOrganizationID)) return false;

                    return GlobalUserPermission.GetEditable("ListStaffNameEditable", this.StaffID);
                }
                catch
                {
                    return false;
                }
            }
        }

        public bool Verifiable
        {
            get
            {
                try
                {
                    if (!GlobalUserPermission.GetUserEditable(GlobalVariables.GlobalUserInformation.UserID, GlobalEnum.TaskID.ListStaffNameVerifiable, this.UserOrganization.UserOrganizationID)) return false;

                    return GlobalUserPermission.GetEditable("ListStaffNameEditable", this.StaffID);
                }
                catch
                {
                    return false;
                }
            }
        }

        public bool Unverifiable
        {
            get
            {
                try
                {
                    if (!GlobalUserPermission.GetUserEditable(GlobalVariables.GlobalUserInformation.UserID, GlobalEnum.TaskID.ListStaffNameUnverifiable, this.UserOrganization.UserOrganizationID)) return false;

                    return GlobalUserPermission.GetEditable("ListStaffNameEditable", this.StaffID);
                }
                catch
                {
                    return false;
                }
            }
        }


        #endregion Object Permission






        public void Fill(int staffID)
        {
            if (this.StaffID == staffID) this.StaffID = -1; //Enforce to reload
            this.StaffID = staffID;
        }

        public void New()
        {
            if (this.StaffID == 0) this.StaffID = -1;
            this.StaffID = 0;
        }

        public void Edit()
        {

        }

        #region Save & Delete Method


        public bool Save()
        {
            int customerTypeID = 0;

            try
            {

                if (!this.SaveValidate()) throw new System.ArgumentException("Insufficient save", "Save validate");

                using (TransactionScope transactionScope = new TransactionScope())
                {
                    if (this.ReadOnly) throw new System.ArgumentException("Insufficient save", "Uneditable");

                    if (!this.SaveMaster(ref customerTypeID)) throw new System.ArgumentException("Insufficient save", "Save master");

                    if (!this.SaveDetail(customerTypeID)) throw new System.ArgumentException("Insufficient save", "Save detail");

                    transactionScope.Complete();
                }

                //SQLDatabase.ExecuteNonQuery("ListStaffNameUpdateHierarchyLevel", CommandType.StoredProcedure, "AncestorID", this.listStaffNameMaster.AncestorID);

                this.Fill(customerTypeID);
                return true;
            }
            catch (System.Exception exception)
            {
                throw exception;
            }
        }


        public bool Delete()
        {
            if (this.listStaffNameMaster.StaffID <= 0) return false;

            try
            {

                if (!this.SaveValidate()) throw new System.ArgumentException("Insufficient delete", "Delete validate");

                using (TransactionScope transactionScope = new TransactionScope())
                {
                    if (!this.Editable) throw new System.ArgumentException("Insufficient delete", "Uneditable");

                    if (!this.SaveUndo(this.listStaffNameMaster.StaffID)) throw new System.ArgumentException("Insufficient delete", "Delete detail");

                    if (this.MasterTableAdapter.Delete(this.listStaffNameMaster.StaffID) != 1) throw new System.ArgumentException("Insufficient delete", "Delete master");

                    transactionScope.Complete();
                }
                this.Fill(0);
                return true;
            }
            catch (System.Exception exception)
            {
                throw exception;
            }
        }


        private bool SaveValidate()
        {
            ExceptionTable exceptionTable = new ExceptionTable(new string[2, 2] { { "ExceptionCategory", "System.String" }, { "ExceptionDescription", "System.String" } });

            this.UserOrganization = GlobalUserPermission.GetUserInformation(this.UserOrganization.UserID, this.ListStaffNameMaster.EntryDate);

            if (this.UserOrganization.UserID <= 0 || this.UserOrganization.UserOrganizationID <= 0) exceptionTable.AddException(new string[] { GlobalVariables.stringFieldRequired, "User information" });

            if (exceptionTable.Table.Rows.Count <= 0 && this.IsValid) return true; else throw new CustomException("Save validate", exceptionTable.Table);
        }


        private bool SaveMaster(ref int customerTypeID)
        {
            ListStaffNameDTS.ListStaffNameDataTable masterDataTable;
            ListStaffNameDTS.ListStaffNameRow masterRow;

            if (this.listStaffNameMaster.StaffID <= 0) //Add
            {
                masterDataTable = new ListStaffNameDTS.ListStaffNameDataTable();
                masterRow = masterDataTable.NewListStaffNameRow();
            }
            else //Edit
            {
                if (!this.SaveUndo(listStaffNameMaster.StaffID)) throw new System.ArgumentException("Insufficient save", "Save undo");
                masterDataTable = this.MasterTableAdapter.GetData(listStaffNameMaster.StaffID);
                if (masterDataTable.Count > 0) masterRow = masterDataTable[0]; else throw new System.ArgumentException("Insufficient save", "Get for edit");
            }

            masterRow.EntryDate = this.listStaffNameMaster.EntryDate;

            masterRow.StaffCategoryID = this.listStaffNameMaster.StaffCategoryID;

            masterRow.Description = this.listStaffNameMaster.Description;
            masterRow.DescriptionOfficial = this.listStaffNameMaster.DescriptionOfficial;
            masterRow.DescriptionOriginal = this.listStaffNameMaster.DescriptionOriginal;

            masterRow.InActive = this.listStaffNameMaster.InActive;

            masterRow.UserID = this.UserOrganization.UserID;
            masterRow.UserOrganizationID = this.UserOrganization.UserOrganizationID;

            if (this.listStaffNameMaster.StaffID <= 0) masterDataTable.AddListStaffNameRow(masterRow);

            int rowsAffected = this.MasterTableAdapter.Update(masterRow);

            customerTypeID = masterRow.StaffID;

            return rowsAffected == 1;

        }


        private bool SaveDetail(int customerTypeID)
        {
            int serialID = 0; int rowsAffected = 0;


            #region <Save collection>

            serialID = 0;

            ListStaffNameDTS.ListStaffNameDetailDataTable detailDataTable = new ListStaffNameDTS.ListStaffNameDetailDataTable();

            foreach (ListStaffNameDetail listStaffNameDetail in this.ListStaffNameDetailList)
            {
                ListStaffNameDTS.ListStaffNameDetailRow detailRow = detailDataTable.NewListStaffNameDetailRow();

                detailRow.StaffID = customerTypeID;
                detailRow.SerialID = ++serialID;

                detailRow.CommonID = listStaffNameDetail.CommonID;
                detailRow.CommonValue = listStaffNameDetail.CommonValue;

                detailRow.Remarks = listStaffNameDetail.Remarks;

                detailDataTable.AddListStaffNameDetailRow(detailRow);
            }

            rowsAffected = this.DetailTableAdapter.Update(detailDataTable);
            if (rowsAffected != this.listStaffNameDetailList.Count) throw new System.ArgumentException("Insufficient save", "Save detail");


            #endregion <Save collection>


            return true;
        }


        private bool SaveUndo(int staffID)
        {
            this.DetailTableAdapter.Delete(staffID);

            return true;
        }



        #endregion



        private void RestoreProcedure()
        {
            string queryString;
            string[] queryArray;



            queryString = "     " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";

            queryString = queryString + "       SELECT      CAST(0 AS bit) AS IsStaff, 100000 * StaffCategoryID AS StaffID, Description, 100000 * AncestorID AS AncestorID, EntryDate " + "\r\n";
            queryString = queryString + "       FROM        ListStaffCategory " + "\r\n";

            queryString = queryString + "       UNION ALL " + "\r\n";

            queryString = queryString + "       SELECT      CAST(1 AS bit) AS IsStaff, StaffID, DescriptionOfficial + ' ' + DescriptionOriginal AS Description, 100000 * StaffCategoryID AS AncestorID, EntryDate " + "\r\n";
            queryString = queryString + "       FROM        ListStaffName " + "\r\n";

            SQLDatabase.CreateStoredProcedure("ListStaffNameListing", queryString);






            queryString = "     @StaffID Int " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       SELECT      StaffID, StaffCategoryID, Description, DescriptionOfficial, DescriptionOriginal, InActive, EntryDate, UserID, UserOrganizationID " + "\r\n";
            queryString = queryString + "       FROM        ListStaffName " + "\r\n";
            queryString = queryString + "       WHERE       StaffID = @StaffID " + "\r\n";

            SQLDatabase.CreateStoredProcedure("ListStaffNameSelect", queryString);


            queryString = "     @StaffCategoryID int, @Description nvarchar(100), @DescriptionOfficial nvarchar(100), @DescriptionOriginal nvarchar(100), @InActive bit, @EntryDate datetime, @UserID int, @UserOrganizationID int " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       INSERT INTO ListStaffName (StaffCategoryID, Description, DescriptionOfficial, DescriptionOriginal, InActive, EntryDate, UserID, UserOrganizationID) VALUES (@StaffCategoryID, @Description, @DescriptionOfficial, @DescriptionOriginal, @InActive, @EntryDate, @UserID, @UserOrganizationID) " + "\r\n";
            queryString = queryString + "       SELECT      StaffID, StaffCategoryID, Description, DescriptionOfficial, DescriptionOriginal, InActive, EntryDate, UserID, UserOrganizationID FROM ListStaffName WHERE StaffID = SCOPE_IDENTITY() " + "\r\n";

            SQLDatabase.CreateStoredProcedure("ListStaffNameInsert", queryString);


            queryString = "     @StaffID int, @StaffCategoryID int, @Description nvarchar(100), @DescriptionOfficial nvarchar(100), @DescriptionOriginal nvarchar(100), @InActive bit, @EntryDate datetime, @UserID int, @UserOrganizationID int " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       UPDATE      ListStaffName SET StaffCategoryID = @StaffCategoryID, Description = @Description, DescriptionOfficial = @DescriptionOfficial, DescriptionOriginal = @DescriptionOriginal, InActive = @InActive, EntryDate = @EntryDate, UserID = @UserID, UserOrganizationID = @UserOrganizationID WHERE StaffID = @StaffID " + "\r\n";
            queryString = queryString + "       SELECT      StaffID, Description, EntryDate, UserID, UserOrganizationID FROM ListStaffName WHERE StaffID = @StaffID " + "\r\n";

            SQLDatabase.CreateStoredProcedure("ListStaffNameUpdate", queryString);


            queryString = " @StaffID int ";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       DELETE FROM ListStaffName WHERE StaffID = @StaffID " + "\r\n";
            SQLDatabase.CreateStoredProcedure("ListStaffNameDelete", queryString);






            queryString = " @StaffID int " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       SELECT      StaffID, SerialID, CommonID, CommonValue, Remarks " + "\r\n";
            queryString = queryString + "       FROM        ListStaffNameDetail " + "\r\n";
            queryString = queryString + "       WHERE       StaffID = @StaffID " + "\r\n";

            SQLDatabase.CreateStoredProcedure("ListStaffNameDetailSelect", queryString);


            queryString = " @StaffID int, @SerialID int,	@CommonID int, @CommonValue float, @Remarks nvarchar(100) " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       INSERT INTO ListStaffNameDetail (StaffID, SerialID, CommonID, CommonValue, Remarks) VALUES (@StaffID, @SerialID, @CommonID, @CommonValue, @Remarks) " + "\r\n";
            queryString = queryString + "       SELECT      StaffID, SerialID, CommonID, CommonValue, Remarks FROM ListStaffNameDetail WHERE (StaffID = @StaffID) AND (SerialID = @SerialID) " + "\r\n";

            SQLDatabase.CreateStoredProcedure("ListStaffNameDetailInsert", queryString);



            queryString = " @StaffID int, @SerialID int,	@CommonID int, @CommonValue float, @Remarks nvarchar(100) " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       UPDATE      ListStaffNameDetail SET CommonID = @CommonID, CommonValue = @CommonValue, Remarks = @Remarks WHERE StaffID = @StaffID AND SerialID = @SerialID " + "\r\n";
            queryString = queryString + "       SELECT      StaffID, SerialID, CommonID, CommonValue, Remarks FROM ListStaffNameDetail WHERE StaffID = @StaffID AND SerialID = @SerialID " + "\r\n";

            SQLDatabase.CreateStoredProcedure("ListStaffNameDetailUpdate", queryString);



            queryString = " @StaffID int " + "\r\n";
            queryString = queryString + " WITH ENCRYPTION " + "\r\n";
            queryString = queryString + " AS " + "\r\n";
            queryString = queryString + "       DELETE FROM ListStaffNameDetail WHERE StaffID = @StaffID " + "\r\n";
            SQLDatabase.CreateStoredProcedure("ListStaffNameDetailDelete", queryString);


      
            /// <summary>
            /// Check for editable
            /// </summary>
            queryArray = new string[3];            
            queryArray[0] = "   SELECT      TOP 1 SalesmenID FROM MarketingProgramMaster WHERE SalesmenID = @FindIdentityID " ;
            queryArray[1] = "   SELECT      TOP 1 RequestedEmployeeID FROM MarketingIncentiveMaster WHERE RequestedEmployeeID = @FindIdentityID OR NotedEmployeeID = @FindIdentityID OR ApprovedEmployeeID = @FindIdentityID " ;
            queryArray[2] = "   SELECT      TOP 1 RequestedEmployeeID FROM MarketingPaymentMaster WHERE RequestedEmployeeID = @FindIdentityID OR NotedEmployeeID = @FindIdentityID OR ApprovedEmployeeID = @FindIdentityID " ;

            SQLDatabase.CreateProcedureToCheckExisting("ListStaffNameEditable", queryArray);
        }

    }
}

